/*-----------------------------------------
// Declaration of the Header files required.
------------------------------------------*/



#include "syscall.h"


/*----------------------------------------------------------
// Declare global variables and Data Structures Below
----------------------------------------------------------*/

#define MAX_NO_OF_CLERKS 5
#define MAX_NO_OF_CASHREGISTERS 5
#define MAX_NO_OF_CUSTOMERS 20
#define MAX_NO_OF_AISLE 10
#define MAX_NO_SB 10
#define FALSE 0
#define TRUE 1


/* status values for cashRegisterStatus
 * enum cashRegisterStatusEnum{NOT_SET, CLERK_WAITING, CASHREG_WAITING }; */
#define	NOT_SET 			0
#define CLERK_WAITING		1
#define CASHREG_WAITING		2

/*status values for clerstatus
 * enum clerkStatusEnum{CLERK_FREE, CLERK_BUSY, CLERK_ONBREAK, CLERK_COMING_FROM_BREAK}; */
#define CLERK_FREE					0
#define CLERK_BUSY					1
#define CLERK_ONBREAK				2
#define CLERK_COMING_FROM_BREAK		3


#define MAX_NAME_SIZE   	30
/*buffer to hold the names of lock and CV's and MV's*/
char name[MAX_NAME_SIZE];

/*Customer data sturcture*/
typedef struct customer
{
	int noOfItemsToBePurchased;
	int itemsToBePurchased[10];
	int customerReturning;
	/*customer()
	{
		noOfItemsToBePurchased=(int)((GetRand()%10)+1);
		for(int i=0;i<noOfItemsToBePurchased;i++)
		{
			itemsToBePurchased[i]=(int)(GetRand()%10);
		}
		if(GetRand()%5==4){
			customerReturning=true;
		}
		else{
			customerReturning=false;
		}
	}*/

}customerDataTemplate;




/* cashregister data-structure*/

/*typedef struct cashregister
{

	/* only clerkLock[] should access this data member
	int customerAmount;
	/* only manager_CashRegisterLock should access this data member
	int totalAmount;
	/*totalsales at this cash counter
	int totalSalesAtCashRegister;

	cashregister(){

		customerAmount = 0;
		totalAmount = 0;
		totalSalesAtCashRegister = 0;
	}
}cashRegisterTemplate;*/

int cr_customerAmount[MAX_NO_OF_CASHREGISTERS];
int cr_totalAmount[MAX_NO_OF_CASHREGISTERS];
int cr_totalSalesAtCashRegister[MAX_NO_OF_CASHREGISTERS];


int custThreadCntr;
int cashRegThreadCntr;
int clerkThreadCntr;
int sbThreadCntr;

int custThreadCntrLock;
int cashRegThreadCntrLock;
int clerkThreadCntrLock;
int sbThreadCntrLock;

int testcase;
int noOfClerks;		/* values will change dynamically*/
int noOfCashReg;
int noOfCustomers;
int noOfStockBoys;
int noOfAisle;
/*cashRegisterTemplate cashRegister[MAX_NO_OF_CASHREGISTERS];*/
customerDataTemplate customerData[MAX_NO_OF_CUSTOMERS];



int itemsInStoreInfo[MAX_NO_OF_AISLE]={1,2,3,4,5,6,7,8,9,10} ;

/*------------------------------------------------------------------------
 Declare Locks, CV and Monitor Variables for Customer/Clerk Interaction
------------------------------------------------------------------------*/


/*Lock to  print multiple PRINT Syscalls*/
int printLock;

/*Lock for mutual exclusion on entering line.*/
int clerkLineLock;
/*Locks for each clerk interaction.*/
int clerkLock[MAX_NO_OF_CLERKS];
/*condition to wait on a line for checkout*/
int clerkLineCV[MAX_NO_OF_CLERKS];
/*condition to interaction btw one customer and clerk at a time.*/
int clerkTalkCV[MAX_NO_OF_CLERKS];
/*Condition Variable for Clerks waiting on a break*/
int clerkOnBreakCV;
/* maintains the length of each line.*/
int clerkLineLength[MAX_NO_OF_CASHREGISTERS];
/*maintains the status of each clerk.*/
int clerkStatus[MAX_NO_OF_CLERKS];


/*all to be used for checkout process. To be used under clerkLock[i].*/
int itemId[MAX_NO_OF_CLERKS];
/*to notify that the last item will be processed for each customer/clerk/cash register transaction.*/
int lastItem[MAX_NO_OF_CLERKS];
/*to store the value of customer id so that clerk and cash register know who they are serving.*/
int customerId[MAX_NO_OF_CLERKS];
/*to store the total bill amount for each customer/clerk/cash register transaction.*/
int receiptBillAmount[MAX_NO_OF_CLERKS];
/* will help each clerk and cash register know if the customer wants to buy or return items.*/
int isCustomerReturning[MAX_NO_OF_CLERKS];/*to check if it is buying or returning customer*/
/*to be used with clerkLineLock*/
int signalingClerk; /* To store Id of clerk who call manager when line is above 4*/




/*------------------------------------------------------------------------
 Declare Locks, CV and Monitor Variables for Clerk/CashRegister Interaction
------------------------------------------------------------------------*/

/*All these variables would be modified with the clerkLock[i]
differnet states a cash register can be in.*/

/*for clerk and cash reg interaction.*/
int cashRegisterCV[MAX_NO_OF_CASHREGISTERS];
/*status array for all cash registers.*/
int cashRegisterStatus[MAX_NO_OF_CASHREGISTERS];


/*------------------------------------------------------------------------------
// Declare Locks, CV and Monitor Variables for Manager/Cash Register Interaction
//------------------------------------------------------------------------------*/

/*Lock for Mutual Exclusion between Manager and Cash Register*/
/*No CV's or Monitor variables between them*/
int manager_CashRegisterLock[MAX_NO_OF_CASHREGISTERS];
int amountNeeded[MAX_NO_OF_CASHREGISTERS];/*amount needed by cash register to give to customer returning items*/
int cashRegisterWaitingCV[MAX_NO_OF_CASHREGISTERS];

/*------------------------------------------------------------------------------
// Declare Locks, CV and Monitor Variables for Customer/StockBoy/Aisle Interaction
//------------------------------------------------------------------------------*/


/* lock to check the status of stock boy maintianing the mutual exclusion.*/
int sbStatusLock;
/* sbStatus for maintianing the status of each stockboy	-1=free		-2=on break	>=0 In store doing stuff*/
int sbStatus[MAX_NO_SB];
/*maintain the length of the customer needing help in each aisle.*/
int aisleHelpLineLength[MAX_NO_OF_AISLE];
/* to wait on the aisle for help.*/
int aisleHelpCV[MAX_NO_OF_AISLE];

/*access stock room one at time.*/
int stockRoomLock;
int stockRoomStatus;/*to be used with stockRoomLock*/
int stockRoomWaitCV;

/*access the restock list maintianing the data consistency.*/
int reStockListLock;

/*lock for updating the Qty on each aisle.*/
int aisleQtyLock[MAX_NO_OF_AISLE];
/*maintain the Qty on each aisle*/
int aisleQty[MAX_NO_OF_AISLE];
/*if the Qty on aisle is empty, wait till restocked.*/
int aisleEmptyCV[MAX_NO_OF_AISLE];


/* Lock for the button when no SB available.*/
int noSBPushButtonLock;
/* customers wait till SB is woken by manager.*/
int noSBPushButtonCV;
/*stock boys wait till SB is woken by manager.*/
int sbOnBreakCV;
/* maintains the length of the line waiting on the pushbutton.*/
int noSBPushButtonLineLength;

/* lock on each SB.*/
int sbLock[MAX_NO_SB];
/* wait on SB.*/
int sbCV[MAX_NO_SB];
/*For the Customer and SB ping pong.*/
int sbCustQA[MAX_NO_SB][2];


/*------------------------------------------------------------------------------
// Declare Locks, CV and Monitor Variables for Manager Interaction
//------------------------------------------------------------------------------*/

/*Customer waiting when all clerks are on break*/
int custWaitingCV;/* This CV should be used with clerkLineLock*/
int allClerksOnBreak;
/*Clerks signaling manager to wakeup another clerk if their linelength>4*/
int wakeUpAClerk;/* This CV should be used with clerkLineLock*/
/*variable modified by customers and read by manager to make note of end of simulation*/
int totalcustomersexited;






/*----------------------------------------------
// Functions for all different types of Threads
//----------------------------------------------

//--------Customer Thread Starts Here-----------*/

void Customer()
{
	int threadId;
	int failureProbablity;
	int counter;
	int currentItemId;
	/*For finding the shortest length. Also the Total customers in a line cannot be more than 99999*/
	int shortestLineLength=100000;
	int mySB;
	int *restockItem;
	int itemAisleId,y,i;
	/* For finding the index of the line with shortest length.	*/
	int shortestLineIndex=-1;
	int sbFound=FALSE;

	Acquire(custThreadCntrLock);
	
	threadId=GetMV(custThreadCntr);
	Print2("Cust counter is %d: so thread id is %d.\n",GetMV(custThreadCntr),threadId);
	SetMV(custThreadCntr, (GetMV(custThreadCntr)+1));
	Release(custThreadCntrLock);
	
	/*If customer is going to return items then just bypass the item finding code and go to Clerk*/
	if(customerData[threadId].customerReturning){
		Acquire(printLock);
		Print2("Customer [%d] needs to return [%d] no.of items.\n",threadId, customerData[threadId].noOfItemsToBePurchased);
		Release(printLock);
		goto liningForClerk;
	}
	/*===================================Customer's Item Fetching code below===================================*/
	Acquire(printLock);
	Print2("Customer [%d] wants to buy [%d] no.of items. \n",threadId,customerData[threadId].noOfItemsToBePurchased);
	Release(printLock);

	for(currentItemId=0;currentItemId<customerData[threadId].noOfItemsToBePurchased;currentItemId++)
	{
		/* Generating the 25% failure probablity for finding the item.*/
		itemAisleId=customerData[threadId].itemsToBePurchased[currentItemId];
		failureProbablity=(GetRand()%4);
		sbFound=FALSE;

		/*=============================Finding stock boy code below=============================*/
		if(failureProbablity==1)
		{
			/*We need to get help from the stockboy*/
			Acquire(printLock);
			Print2("Customer [%d] is not able to find item [%d] and is searching for StockBoy.\n",threadId,currentItemId);
			Release(printLock);
			Acquire(sbStatusLock);

			/* Finding a stockboy for help*/
			counter=0;
			mySB=itemAisleId;

			/*Iterating for each stockboy*/
			while(counter!=noOfStockBoys)
			{

				/*If sbStatus >= 0, it indicates that the stockboy is in aisle , so select that stockboy.*/
				if(GetMV(sbStatus[mySB])>=0)
				{ 
					int currentAisleNumber = (GetMV(sbStatus[mySB])%MAX_NO_OF_AISLE);
					sbFound=TRUE;
					SetMV(aisleHelpLineLength[currentAisleNumber], GetMV(aisleHelpLineLength[currentAisleNumber])+1);
					Wait(aisleHelpCV[currentAisleNumber],sbStatusLock);

					for(y=0;y<noOfStockBoys;y++)
					{
						if((GetMV(sbStatus[y]))==(currentAisleNumber+MAX_NO_OF_AISLE))
						{

							SetMV(sbStatus[y], GetMV(sbStatus[y])-MAX_NO_OF_AISLE);
							mySB=y;
							break;
						}
					}

					/*sbStatusLock->Release(); It's redundant since there is release after the while loop*/
					break;
				}
				mySB=(mySB+1)% noOfStockBoys;
				counter++;
			}
			Release(sbStatusLock);

			
			/*=============================No SB. PushButton code below=============================*/

			if(!sbFound)
			{
				/*no stockboy found so push button for help*/
				Acquire(printLock);
				Print1("Customer [%d] looked in all aisle for StockBoy. He is now requesting help by pressing service button.\n",threadId);
				Release(printLock);
				Acquire(noSBPushButtonLock);

				/*Incrementing the length for pushButton queue*/
				SetMV(noSBPushButtonLineLength, GetMV(noSBPushButtonLineLength)+1);
				Wait(noSBPushButtonCV,noSBPushButtonLock);

				/*Finding the StockBoy with -3 as the status ; this represents he is ready to serve the PushButton*/
				Release(noSBPushButtonLock);

				Acquire(sbStatusLock);
				for(i=0;i<noOfStockBoys;i++)
				{
					if(GetMV(sbStatus[i]) == -3)
					{

						mySB = i;
						/*Chaging the sbStatus back to default -1;so that no other can pick him up*/
						SetMV(sbStatus[i], -1);
						break;
					}
				}
				Release(sbStatusLock);			
				Acquire(sbLock[mySB]);			
				SetMV(sbCustQA[mySB][0], threadId);
				/*Set the id of the item u want to ask the stock boy about.*/
				SetMV(sbCustQA[mySB][1], currentItemId);

				/*Asking the Stockboy about item.*/
				Signal(sbCV[mySB],sbLock[mySB]);
				Wait(sbCV[mySB],sbLock[mySB]);
				Release(sbLock[mySB]);
			}
			/*============PushButton Code ends here================*/

			else
			{

				Acquire(sbLock[mySB]);
				/*Set Customer id for StockBoy to knw.*/
				SetMV(sbCustQA[mySB][0], threadId);
				/*Set the id of the item u want to ask the stock boy abt.*/
				SetMV(sbCustQA[mySB][1], currentItemId);
				Acquire(printLock);
				Print2("Customer [%d] is asking for assistance from StockBoy [%d].\n",threadId,mySB);
				Release(printLock);
				/*Asking the Stockboy abt item.*/
				Signal(sbCV[mySB],sbLock[mySB]);
				Wait(sbCV[mySB],sbLock[mySB]);
				Acquire(printLock);
				Print3("Customer [%d] got aisle [%d] from StockBoy [%d].\n",threadId,itemAisleId,mySB);
				Release(printLock);
				Release(sbLock[mySB]);
			}
			/*====================StockBoy interaction code ends here.=====================*/

		} /* end of item not found loop
		

		///////================Customer fetch the item code below============

		//Acquiring the lock on the aisle where the item has to be pickeup from.*/
		Acquire(aisleQtyLock[itemAisleId]);
		/* checking if the aisleQty is 0 or not.*/
		if(GetMV(aisleQty[itemAisleId])==0)
		{
			/* If 0 then wait for the item to be restocked.*/
			Wait(aisleEmptyCV[itemAisleId],aisleQtyLock[itemAisleId]);
		}
		/*decrementing the Qty by 1.*/
		
			Acquire(printLock);
			Print3("Customer [%d] is picking item of type [%d] from Aisle [%d].\n",threadId,customerData[threadId].itemsToBePurchased[currentItemId],itemAisleId);
			Release(printLock);
		

		SetMV(aisleQty[itemAisleId], GetMV(aisleQty[itemAisleId])-1);

		/*Pushing the item to the list for restocking.*/
		Acquire(reStockListLock);
		ListAppend(customerData[threadId].itemsToBePurchased[currentItemId]);
		Release(reStockListLock);

		/*Checking if more is available on Aisle to signal to the other Customers in case waiting for same item/aisle.*/
		if(GetMV(aisleQty[itemAisleId])>0)
		{
			Signal(aisleEmptyCV[itemAisleId],aisleQtyLock[itemAisleId]);
		}
		Release(aisleQtyLock[itemAisleId]);

		/*================Customer fetch the item code ends here==============*/


	} /* end of customer item pickup loop


	///======================End of Customer Fetching all items code here====================


	/////======Finding shortest line and waiting checkout code below========================*/

liningForClerk:/*label for bypassing item finding code for customers returning items*/

	/*Acquire the lock on clerkLine to find the Shortest line length maintaining the mutual exclusion*/
	Acquire(clerkLineLock);

findshortestline:
	/*Find shortest line length and its index*/
	for(i=0; i<noOfClerks; i++)
	{
		if(GetMV(clerkStatus[i])==CLERK_ONBREAK)
		{
			/*  If Clerk is on break than no need to check his line length.*/
			continue;
		}
		/* Check and compare for finding minimum of line length and corrosponding index*/
		if((GetMV(clerkLineLength[i]))<shortestLineLength)
		{
			shortestLineLength=(GetMV(clerkLineLength[i]));
			shortestLineIndex=i;
		}
	}

	/*Case where all clerks and on break*/
	if(shortestLineIndex==-1)
	{
		/*Alert the manager that all clerks are on break*/
		SetMV(allClerksOnBreak, TRUE);
		Wait(custWaitingCV,clerkLineLock);
		goto findshortestline;

	}

	/*==============Shortest Line found. Waiting for checkout==================

	//If customer finds a line with shortest length that has a clerk who is not on break,
	// increment the line length*/
	Acquire(printLock);
	Print3("Customer [%d] chose Clerk [%d] with line length of [%d].\n",threadId,shortestLineIndex, GetMV(clerkLineLength[shortestLineIndex]));
	Release(printLock);
	SetMV(clerkLineLength[shortestLineIndex], GetMV(clerkLineLength[shortestLineIndex])+1);
	Wait(clerkLineCV[shortestLineIndex],clerkLineLock);
	
	/*decrease the line length as the one customer will now be served by the clerk.*/
	SetMV(clerkLineLength[shortestLineIndex], GetMV(clerkLineLength[shortestLineIndex])-1);
	Release(clerkLineLock);

	/*Acquire lock on that clerk so that the checkout process is mutually exclusive.*/
	Acquire(clerkLock[shortestLineIndex]);

	/* Give the clerk items one by one.*/
	SetMV(customerId[shortestLineIndex], threadId);
	/*notify the clerk whether the customer is buying or returning items*/
	SetMV(isCustomerReturning[shortestLineIndex], customerData[threadId].customerReturning);
	

	/*=================Entire CheckOut code below===========================*/

	for(i=0;i<customerData[threadId].noOfItemsToBePurchased;i++)
	{

		/* Setting the id of item passed for the clerk to access*/
		SetMV(itemId[shortestLineIndex] , customerData[threadId].itemsToBePurchased[i]);

		/*Checking for the last item in order to notify the clerk.*/
		if(i==(customerData[threadId].noOfItemsToBePurchased)-1)
		{
			SetMV(lastItem[shortestLineIndex], TRUE);
			
		}
		/* customer will give items one by one to clerk*/
		Acquire(printLock);
		Print3("Customer [%d] gives item [%d] to Clerk [%d].\n",threadId,(i+1),shortestLineIndex);
		Release(printLock);
		Signal(clerkTalkCV[shortestLineIndex],clerkLock[shortestLineIndex]);
		if(i==(customerData[threadId].noOfItemsToBePurchased)-1)
		{
			Acquire(printLock);
			Print3("Customer [%d] tells Clerk [%d], I have given you all my [%d] items.\n",threadId,shortestLineIndex,customerData[threadId].noOfItemsToBePurchased);
			Release(printLock);
		}
		Wait(clerkTalkCV[shortestLineIndex],clerkLock[shortestLineIndex]);
	}
	if(!customerData[threadId].customerReturning)
		{
		Acquire(printLock);
		Print3("Customer [%d] pays $[%d] to Clerk [%d] and is now waiting for receipt.\n",threadId, GetMV(receiptBillAmount[shortestLineIndex]),shortestLineIndex);
		Release(printLock);
		/*Signal the clerk for payment.*/
		Signal(clerkTalkCV[shortestLineIndex],clerkLock[shortestLineIndex]);
		Wait(clerkTalkCV[shortestLineIndex],clerkLock[shortestLineIndex]);
		Acquire(printLock);
		Print2("Customer [%d] got receipt from Clerk [%d] and is now leaving.\n",threadId,shortestLineIndex);
		Release(printLock);
	}
	else{
		Acquire(printLock);
		Print3("Customer [%d] receives $[%d] from Clerk [%d] and is now waiting for receipt.\n",threadId, GetMV(receiptBillAmount[shortestLineIndex]),shortestLineIndex);
		Release(printLock);
		/*Signal the clerk for payment.*/
		Signal(clerkTalkCV[shortestLineIndex],clerkLock[shortestLineIndex]);
		Wait(clerkTalkCV[shortestLineIndex],clerkLock[shortestLineIndex]);
		Acquire(printLock);
		Print2("Customer [%d] got receipt from Clerk [%d] and is now leaving.\n",threadId,shortestLineIndex);
		Release(printLock);
	}

/*=============CheckOut Over. Customer thread will end soon after reseting values=============///

	//Reseting the values to defaults*/
	SetMV(lastItem[shortestLineIndex], FALSE);
	SetMV(itemId[shortestLineIndex], -1);
	SetMV(customerId[shortestLineIndex], -1);
	SetMV(isCustomerReturning[shortestLineIndex], FALSE);
	Release(clerkLock[shortestLineIndex]);
	SetMV(totalcustomersexited, GetMV(totalcustomersexited)+1);
	
	Exit(0);
}

/*============End of Customer Thread Code==================///


=================Cash Register Thread Starts here=========//*/

void CashReg()
{
	int threadId;
	int counter;
	Acquire(cashRegThreadCntrLock);
	threadId=GetMV(cashRegThreadCntr);
	Print2("CashReg counter is %d: so thread id is %d.\n",GetMV(cashRegThreadCntr),threadId);
	SetMV(cashRegThreadCntr, (GetMV(cashRegThreadCntr)+1));
	Release(cashRegThreadCntrLock);
	while(1)
	{

		/*========Clerk Cash Register Checkout code below=======*/
		Acquire(clerkLock[threadId]);
		if(GetMV(cashRegisterStatus[threadId]) == CLERK_WAITING){
			Signal(cashRegisterCV[threadId],clerkLock[threadId]);
			Wait(cashRegisterCV[threadId],clerkLock[threadId]);
		}
		else{
			SetMV(cashRegisterStatus[threadId], CASHREG_WAITING);
			Wait(cashRegisterCV[threadId],clerkLock[threadId]);
		}
	counter=1;
		/*cashRegister is interacting with the clerk for customer billing*/

		while(!GetMV(lastItem[threadId]))
		{
			Acquire(printLock);
			Print3("Cash Register [%d] got item [%d] from Clerk [%d] to scan.\n",threadId,counter,threadId);
			Release(printLock);
			counter++;
			SetMV(cr_customerAmount[threadId], GetMV(cr_customerAmount[threadId]) + itemsInStoreInfo[GetMV(itemId[threadId])]);
			Signal(cashRegisterCV[threadId],clerkLock[threadId]);
			Wait(cashRegisterCV[threadId],clerkLock[threadId]);
		}

		Acquire(printLock);
		Print3("Cash Register [%d] got item [%d] from Clerk [%d] to scan.\n",threadId,counter,threadId);
		Release(printLock);
		/*Add the last item to the total of the customer total amount*/
		SetMV(cr_customerAmount[threadId], GetMV(cr_customerAmount[threadId]) + itemsInStoreInfo[GetMV(itemId[threadId])]);
		Acquire(printLock);
		Print3("Cash Register [%d] has scanned all [%d] items for Customer [%d].\n",threadId,counter, GetMV(customerId[threadId]));
		Release(printLock);
		
		if(GetMV(isCustomerReturning[threadId])){/*customer returning items*/
			/*=========get money from Manager*/
			Acquire(manager_CashRegisterLock[threadId]);
			SetMV(cr_totalSalesAtCashRegister[threadId], GetMV(cr_totalSalesAtCashRegister[threadId]) - GetMV(cr_customerAmount[threadId]));
			SetMV(amountNeeded[threadId], (GetMV(cr_customerAmount[threadId])));
			Acquire(printLock);
			Print2("Cash Register [%d] informed the manager that he needs $[%d].\n",threadId, GetMV(amountNeeded[threadId]));
			Release(printLock);
			Wait(cashRegisterWaitingCV[threadId],manager_CashRegisterLock[threadId]);/*waiting for money from manager*/
			Acquire(printLock);
			Print2("Cash Register [%d] received $[%d] from the manager.\n", threadId, GetMV(amountNeeded[threadId]));
			Release(printLock);
			/*========Received cash from Manager*/
			SetMV(amountNeeded[threadId], 0);
			Release(manager_CashRegisterLock[threadId]);
			/*Clerk would be giving the final amount to the customer from this receiptBillAmount*/
			Acquire(printLock);
			Print3("Cash Register [%d] gave total cost $[%d] for Customer [%d]",threadId, GetMV(cr_customerAmount[threadId]),GetMV(customerId[threadId]));
			Print2(" to Clerk [%d] for [%d] items.\n",threadId,counter);
			Release(printLock);
			Acquire(printLock);
			Print2("Cash Register [%d] gave the money to Clerk [%d].\n",threadId,threadId);
			Release(printLock);
			SetMV(receiptBillAmount[threadId], GetMV(cr_customerAmount[threadId]));
			Signal(cashRegisterCV[threadId],clerkLock[threadId]);
			Wait(cashRegisterCV[threadId],clerkLock[threadId]);

			/*Give the receipt*/
			SetMV(cr_customerAmount[threadId], 0);
			Signal(cashRegisterCV[threadId],clerkLock[threadId]);
			Acquire(printLock);
			Print3("Cash Register [%d] gave receipt to Clerk [%d] for Customer [%d].\n",threadId,threadId, GetMV(customerId[threadId]));
			Release(printLock);
			SetMV(cashRegisterStatus[threadId], NOT_SET);

		}
		else{/*customer buying items
			//Clerk would be getting the final amount for the customer from this receiptBillAmount*/
			Acquire(printLock);	
			Print3("Cash Register [%d] gave total cost $[%d] for Customer [%d]",threadId, GetMV(cr_customerAmount[threadId]), GetMV(customerId[threadId]));
			Print2("to Clerk [%d] for [%d] items.\n",threadId,counter);
			Release(printLock);
			
			SetMV(receiptBillAmount[threadId], GetMV(cr_customerAmount[threadId]));
			Signal(cashRegisterCV[threadId],clerkLock[threadId]);
			Wait(cashRegisterCV[threadId],clerkLock[threadId]);

			/*If I'm here I've got the payment*/
			Acquire(manager_CashRegisterLock[threadId]);
			SetMV(cr_totalAmount[threadId], GetMV(cr_totalAmount[threadId]) + GetMV(cr_customerAmount[threadId]));
			SetMV(cr_totalSalesAtCashRegister[threadId], GetMV(cr_totalSalesAtCashRegister[threadId]) + GetMV(cr_customerAmount[threadId]));
			Release(manager_CashRegisterLock[threadId]);

			SetMV(cr_customerAmount[threadId], 0);
			Acquire(printLock);
			Print2("Cash Register [%d] got the money from Clerk [%d].\n",threadId,threadId);
			Release(printLock);
			Signal(cashRegisterCV[threadId],clerkLock[threadId]);
			Acquire(printLock);
			Print3("Cash Register [%d] gave receipt to Clerk [%d] for Customer [%d].\n",threadId,threadId, GetMV(customerId[threadId]));
			Release(printLock);
			SetMV(cashRegisterStatus[threadId], NOT_SET);
	}

		/*print the total sales till this point*/
		Acquire(manager_CashRegisterLock[threadId]);
		Acquire(printLock);
		Print2("Cash Register [%d] total sale is $[%d].\n",threadId, GetMV(cr_totalSalesAtCashRegister[threadId]));
		Release(printLock);
		Release(manager_CashRegisterLock[threadId]);

		Release(clerkLock[threadId]);
		
	}

}

/*===================Cash Register thread code ends here==============//////



//////===============Clerk thread starts here==================////*/
void Clerk()
{
	int threadId;
	int item;
	int i;
	int myId;
	Acquire(clerkThreadCntrLock);
	threadId=GetMV(clerkThreadCntr);
	Print2("Clerk counter is %d: so thread id is %d.\n",GetMV(clerkThreadCntr),threadId);
	SetMV(clerkThreadCntr, (GetMV(clerkThreadCntr)+1));
	Release(clerkThreadCntrLock);
	/*Clerk thread buying some time before customer's finish purchasing*/
	for(i=0; i<1000; i++){
		Yield();
	}
	/*storing clerk number on index i*/
	myId = threadId;
	while(1)
	{
		/* Acquire clerkLineLock*/
		Acquire(clerkLineLock);
		/*========this infinite loop is for clerk to check on the customerlinelength after coming from a break*/
		while(1)
		{
			/*If there are customers waiting for the clerk, then service them.*/
			/*else go on a break*/
			if(GetMV(clerkLineLength[myId])>0){/*Customers waiting for me*/

				/*if mylinelength>4 inform the manager to wake up another clerk*/
				if(GetMV(clerkLineLength[myId])>3)
				{
					SetMV(wakeUpAClerk, TRUE);
					SetMV(signalingClerk, threadId);
					Acquire(printLock);
					Print1("Clerk [%d] sees more than 4 people in line and calls Manager.\n",threadId);
					Release(printLock);
				}
				/*Wake 1 customer up*/
				Signal(clerkLineCV[myId],clerkLineLock);
				SetMV(clerkStatus[myId], CLERK_BUSY);
				break;
			}
			else{/* No customer waiting for me. Go on a break*/
				SetMV(clerkStatus[myId], CLERK_ONBREAK);
				Acquire(printLock);
				Print2("Clerk [%d] is leaving Cash Register [%d] and going on break.\n",threadId,threadId);
				Release(printLock);
				Wait(clerkOnBreakCV,clerkLineLock);
				Acquire(printLock);
				Print1("Clerk [%d] was called by Manager to work.\n",threadId);
				Release(printLock);
				SetMV(clerkStatus[myId], CLERK_COMING_FROM_BREAK);

				/*Wake up all customers waiting for me*/
				Broadcast(custWaitingCV,clerkLineLock);
				SetMV(clerkStatus[myId], CLERK_FREE);
				Release(clerkLineLock);
				/*buy some time*/
				for(i=0; i<50; i++){
					Yield();
				}
				Acquire(clerkLineLock);
				continue;
			}
		}
		/*Very important to do this. Lock clerkLock before releasing clerkLineLock so that the transition between monitor
		//is smooth. This makes sure the clerk acquires the monitor variables before the customer does. Otherwise it may
		// lead to a deadlock if the clerk above signal to the customer is lost
		
		///=============Clerk Checkout code below=======================///*/
		Acquire(clerkLock[myId]);
		Release(clerkLineLock);
		Wait(clerkTalkCV[myId],clerkLock[myId]);/* Time to play some tennis*/

		/*-------------------------------------------------------------------------
		//  Customer has signaled me. Ball is in my court
		//Setup Interaction with Cash Register*/
		if(GetMV(cashRegisterStatus[myId])!=CASHREG_WAITING){/*if Cash register is not waiting then i wait*/
			SetMV(cashRegisterStatus[myId], CLERK_WAITING);
			Wait(cashRegisterCV[myId],clerkLock[myId]);
		}

		/*Customer has given an item for me to be scanned*/
		item=0; /* index to keep track of item number*/
		while(!GetMV(lastItem[myId])){
			Acquire(printLock);
			Print3("Clerk [%d] got item [%d] from Customer [%d].\n", myId, item, GetMV(customerId[myId]));
			Release(printLock);
			
			/*Passing the baton to Cash Register*/
			Acquire(printLock);
			Print3("Clerk [%d] gave item [%d] to Cash Register [%d] for scanning.\n",threadId,item,threadId);
			Release(printLock);
			item++;
			Signal(cashRegisterCV[myId],clerkLock[myId]);
			Wait(cashRegisterCV[myId],clerkLock[myId]);
			/*Asking Customer to scan the next item*/
			Signal(clerkTalkCV[myId],clerkLock[myId]);
			Wait(clerkTalkCV[myId],clerkLock[myId]);
		}
		/*Passing the baton to Cash Register for the last item*/
		Acquire(printLock);
		Print3("Clerk [%d] got item [%d] from Customer [%d].\n", myId, item, GetMV(customerId[myId]));
		Release(printLock);
		Acquire(printLock);
		Print3("Clerk [%d] gave item [%d] to Cash Register [%d] for scanning.\n",threadId,item,threadId);
		Release(printLock);

		Signal(cashRegisterCV[myId],clerkLock[myId]);
		Wait(cashRegisterCV[myId],clerkLock[myId]);
		Acquire(printLock);
		Print3("Clerk [%d] got total cost $[%d] from Cash Register [%d].\n",threadId, GetMV(receiptBillAmount[threadId]),threadId);
		Release(printLock);
		/*Passing the bill to the customer*/
		Acquire(printLock);
		Print3("Clerk [%d] tells Customer [%d] total cost is $[%d].\n", myId, GetMV(customerId[myId]), GetMV(receiptBillAmount[threadId]));
		Release(printLock);
		if(GetMV(isCustomerReturning[threadId])){/*returning customer*/
			Acquire(printLock);
			Print3("Clerk [%d] got money $[%d] from Cash Register [%d].\n", myId, GetMV(receiptBillAmount[threadId]), myId);
			Release(printLock);
			Acquire(printLock);
			Print3("Clerk [%d] gave the money $[%d] to Customer [%d].\n", myId, GetMV(receiptBillAmount[threadId]), GetMV(customerId[myId]));
			Release(printLock);
		}
		Signal(clerkTalkCV[myId],clerkLock[myId]);
		Wait(clerkTalkCV[myId],clerkLock[myId]);
		/*Got Money from Customer. Give it to cash register*/
		if(!GetMV(isCustomerReturning[threadId])){/*buying customer*/
			Acquire(printLock);
			Print3("Clerk [%d] got money $[%d] from Customer [%d].\n",threadId, GetMV(receiptBillAmount[threadId]), GetMV(customerId[myId]));
			Release(printLock);
			Acquire(printLock);
			Print3("Clerk [%d] gave the money $[%d] to Cash Register [%d].\n",threadId, GetMV(receiptBillAmount[threadId]),threadId);
			Release(printLock);
		}
		Signal(cashRegisterCV[myId],clerkLock[myId]);
		Wait(cashRegisterCV[myId],clerkLock[myId]);
		Acquire(printLock);
		Print2("Clerk [%d] got receipt from Cash Register [%d].\n",threadId,threadId);
		Release(printLock);
		/*Got Receipt from Cash Register. Give it to Customer*/
		Acquire(printLock);
		Print2("Clerk [%d] gave the receipt to Customer [%d] and tells him to leave.\n",threadId, GetMV(customerId[myId]));
		Release(printLock);
		Signal(clerkTalkCV[myId],clerkLock[myId]);
		Release(clerkLock[myId]);
		/*==============Clerk checkout code ends here=======================
		//Setting clerk status to free. waiting for other customer or will go on break.*/
		Acquire(clerkLineLock);
		SetMV(clerkStatus[myId], CLERK_FREE);
		Release(clerkLineLock);

	}
}
/*=================Clerk thread code ends here=================///////////

//////===============Manager Thread Code will start here=========//////////*/

void Manager(int threadId)
{
	int totalSales=0;
	int takeCashProb;
	int i;
	/*Manager will check for end of simulation when all customer have left the Depot.*/
	while(GetMV(totalcustomersexited) != noOfCustomers){/*this checks for end of simulation*/
		/*Wakeup clerks if they are on break and customer needs them*/
		Acquire(clerkLineLock);
		/*Will wake up ALL clerk if all are on break and customers waiting.*/
		if(GetMV(allClerksOnBreak)){

			SetMV(allClerksOnBreak, FALSE);
			Broadcast(clerkOnBreakCV,clerkLineLock);
		}
		/*will wake up a clerk of clerk siganls that some line length is more than 4.*/
		else if(GetMV(wakeUpAClerk)){
			Acquire(printLock);
			Print1("Manager got a call from Clerk [%d].\n", GetMV(signalingClerk));
			Release(printLock);
			SetMV(wakeUpAClerk, FALSE);
			Signal(clerkOnBreakCV,clerkLineLock);
			Acquire(printLock);
			Print("Manager wakes up Clerk.\n");
			Release(printLock);
		}
		Release(clerkLineLock);

		/*Empty the Cash Register and display the total sales till that point of time.
		//Will take cash out only randomly from all cash registers.*/
		 takeCashProb=(GetRand()%5);
		if(takeCashProb == 4)
		{
			for(i=0; i<noOfCashReg; i++){

				Acquire(manager_CashRegisterLock[i]);
				if(GetMV(amountNeeded[i])>0){
					totalSales = totalSales - GetMV(amountNeeded[i]);
					Acquire(printLock);
					Print2("Manager gave $[%d] to cash register [%d].\n", GetMV(amountNeeded[i]), i);
					Release(printLock);
					Signal(cashRegisterWaitingCV[i],manager_CashRegisterLock[i]);
				}
				totalSales = totalSales + GetMV(cr_totalAmount[i]);
				if(GetRand()%10==9){
					Acquire(printLock);
					Print1("Manager emptied Cash Register [%d] drawer.\n",i);
					Release(printLock);
					Acquire(printLock);
					Print1("Manager has total sale of $[%d].\n", totalSales);
					Release(printLock);
					Acquire(printLock);
					Print1("Cash Register [%d] drawer is emptied by Manager.\n",i);
					Release(printLock);
					Acquire(printLock);
					Print2("Cash Register [%d] total sale until now is $[%d].\n",i, GetMV(cr_totalSalesAtCashRegister[i]));
					Release(printLock);
				}
				SetMV(cr_totalAmount[i], 0);
				Release(manager_CashRegisterLock[i]);
			}
			if(GetRand()%25==20){
				Acquire(printLock);
				Print1("-------Total Sale of the entire store until now is $[%d]---------\n",totalSales);
				Release(printLock);
			}
		}
		/*Wakeup StockBoys if they are on break and they are needed by some customers*/
		Acquire(noSBPushButtonLock);
		if(GetMV(noSBPushButtonLineLength)>0){/*wake up a stock boy*/
			Acquire(printLock);
			Print("Manager wakes up StockBoy.\n");
			Release(printLock);
			Signal(sbOnBreakCV,noSBPushButtonLock);
		}
		Release(noSBPushButtonLock);

		/* manager will check if there are items to be restocked. if yes he will wake up all stock boys on break.*/
		Acquire(reStockListLock);
		if(!IsListEmpty()){
			Release(reStockListLock);
			Acquire(noSBPushButtonLock);
			Broadcast(sbOnBreakCV,noSBPushButtonLock);
			Release(noSBPushButtonLock);
		}
		Release(reStockListLock);
		Yield();
	}/*end of while*/
	for(i=0;i<1000;i++)
	{
		Yield();
	}
	/*Empty the cash register drawers*/
	for(i=0; i<noOfCashReg; i++){
			Acquire(manager_CashRegisterLock[i]);
			totalSales = totalSales + GetMV(cr_totalAmount[i]);
			SetMV(cr_totalAmount[i], 0);
			Release(manager_CashRegisterLock[i]);
		}
	/*Print out the total sales of individual cash register*/
	for(i=0; i<noOfCashReg; i++){
		Acquire(manager_CashRegisterLock[i]);
			Acquire(printLock);
			Print2("Total Sale from Cash Register [%d] is $[%d].\n",i, GetMV(cr_totalSalesAtCashRegister[i]));
			Release(printLock);
		Release(manager_CashRegisterLock[i]);
	}

	/*#####################Simulation ends when code will reach here###################////////*/
	Acquire(printLock);
	Print1("Total Sale of the entire store is $[%d].\n",totalSales);
	Release(printLock);
	
	Exit(0);
}
/*=========Manager thread will end here==========//

///=========StockBoy thread will begin here===========//*/
void StockBoy()
{
	int threadId;
	int myId;
	int i;
	
	Acquire(sbThreadCntrLock);

	threadId=GetMV(sbThreadCntr);
	Print2("SB counter is %d: so thread id is %d.\n",GetMV(sbThreadCntr),threadId);
	SetMV(sbThreadCntr, (GetMV(sbThreadCntr)+1));
	Release(sbThreadCntrLock);
	 myId = threadId;

	/*Stockboy thread buying some time for customers to buy items*/
	for(i=0; i<25; i++)
	{
		Yield();
	}

	while(1)
	{
		int myaisle=-1;	/* index to know the aisle that i need to restock*/
		Acquire(reStockListLock);
		Acquire(printLock);
		Print1("StockBoy [%d] is checking if more items are to be re-stocked.\n",myId);
		Release(printLock);
		if(!IsListEmpty())/*if restock list is not empty then go to the stock room to get the item*/
		{
			myaisle = ListRemove();/*Remove the item to be restocked from the list*/
			Release(reStockListLock);
			Acquire(printLock);
			Print2("StockBoy [%d] goes back to stock room for item [%d].\n",myId,myaisle);
			Release(printLock);
			/*Get into the stock room to obtain the item*/
			Acquire(stockRoomLock);
			if(GetMV(stockRoomStatus)==-1){
				SetMV(stockRoomStatus, myId);
			}
			else{
				Acquire(printLock);
				Print2("StockBoy [%d] is waiting for StockBoy [%d] to leave the stock room.\n",myId, GetMV(stockRoomStatus));
				Release(printLock);
				Wait(stockRoomWaitCV,stockRoomLock);
			}
			Release(stockRoomLock);
			/*Spend some time in the stock room*/
			Acquire(printLock);
			Print1("StockBoy [%d] is in stock room.\n",threadId);
			Release(printLock);
			for(i=0; i<1; i++)
			{
					Yield();
			}
			Acquire(printLock);
			Print2("StockBoy [%d] retrieve one new item [%d] from stock room.\n",threadId,myaisle);
			Release(printLock);
			Acquire(printLock);
			Print1("StockBoy [%d] leaves stock room.\n",threadId);
			Release(printLock);
			Acquire(stockRoomLock);
			Signal(stockRoomWaitCV,stockRoomLock);
			SetMV(stockRoomStatus, -1);
			Release(stockRoomLock);
			/*Out of the stock room*/
		}
		

		if(myaisle==-1)/*There is nothing to restock*/
		{
			Release(reStockListLock);/*if no item to restock, release restock list*/
			Acquire(sbStatusLock);
			Acquire(printLock);
			Print1("StockBoy [%d] is going on break.\n",threadId);
			Release(printLock);
			SetMV(sbStatus[myId], -2);/*off to break*/
			
			Release(sbStatusLock);
			
			/*on break*/
			Acquire(noSBPushButtonLock);
			Wait(sbOnBreakCV,noSBPushButtonLock);
			Acquire(printLock);
			Print1("StockBoy [%d] got call from Manager.\n",threadId);
			Release(printLock);
			Release(noSBPushButtonLock);
			
			/*Back to work*/
			Acquire(sbStatusLock);
			SetMV(sbStatus[myId], -1);/*default state*/
			Release(sbStatusLock);
			
			/* coming back from break*/
			Acquire(noSBPushButtonLock);
			while(GetMV(noSBPushButtonLineLength)>0){
				SetMV(noSBPushButtonLineLength, GetMV(noSBPushButtonLineLength)-1);
				Signal(noSBPushButtonCV,noSBPushButtonLock);
				Acquire(sbStatusLock);
				SetMV(sbStatus[myId], -3);
				Acquire(sbLock[myId]);				
				Release(sbStatusLock);
				Release(noSBPushButtonLock);
				Wait(sbCV[myId],sbLock[myId]);
				/*Ping-Pong*/
				
				Signal(sbCV[myId],sbLock[myId]);
				Release(sbLock[myId]);

				Acquire(noSBPushButtonLock);/*Acquire this lock for the while loop*/
			}
			Release(noSBPushButtonLock);
			continue;/*start from the infinite while loop*/
		}/*end of (if(myaisle==-1))*/

		else/*I have to restock an item*/
		{
			/*change my status to the aisle i am in*/
			Acquire(sbStatusLock);
			SetMV(sbStatus[myId], myaisle);
			Release(sbStatusLock);
			
			/*Spending some time in the aisle		*/	
			for(i=0; i<25; i++)
			{
				Yield();
			}
			/*Restock the item;*/
			Acquire(aisleQtyLock[myaisle]);
			
				Acquire(printLock);
				Print3("Stockboy [%d] is restocking item [%d] on Aisle [%d].\n",threadId,myaisle,myaisle);
				Release(printLock);
			
			SetMV(aisleQty[myaisle], GetMV(aisleQty[myaisle])+1);
			Signal(aisleEmptyCV[myaisle],aisleQtyLock[myaisle]);/*If any customer is waiting for an item, then signal him*/
			Release(aisleQtyLock[myaisle]);

			/*See if any customer is waiting for my service*/
			Acquire(sbStatusLock);
			while(GetMV(aisleHelpLineLength[myaisle])>0)
			{
				Signal(aisleHelpCV[myaisle],sbStatusLock);
				SetMV(aisleHelpLineLength[myaisle], GetMV(aisleHelpLineLength[myaisle])-1);	/*Decrement the aisle length*/
				SetMV(sbStatus[myId], GetMV(sbStatus[myId]) + MAX_NO_OF_AISLE);/*increment to signal customer that i am free*/
				Acquire(sbLock[myId]);
				Release(sbStatusLock);
				Wait(sbCV[myId],sbLock[myId]);
				Acquire(printLock);
				Print2("StockBoy [%d] is approached by Customer [%d] for assistance.\n",threadId, GetMV(sbCustQA[myId][0]));
				Release(printLock);
				/*Time to play ping pong*/
				Acquire(printLock);
				Print3("StockBoy [%d] gave aisle [%d] to Customer [%d]",threadId, GetMV(sbCustQA[myId][1]), GetMV(sbCustQA[myId][0]));
				Print1("for item [%d].\n", GetMV(sbCustQA[myId][1]));
				Release(printLock);
				Signal(sbCV[myId],sbLock[myId]);
				Release(sbLock[myId]);				

				/*Acquire sbStatusLock again for the while*/
				Acquire(sbStatusLock);
			}
			/*end of customer service*/
			SetMV(sbStatus[myId], -1);
			Release(sbStatusLock);
		}/*end of else block of restocking and customer service*/
	}/*end of infinite while loop*/
}/*end of function*/

/*===Stock Boy thread ends here================//




/*switch case for Sprintf */
void SwitchSprintf(int id, int index)
{

	switch(id){
		case 0:
		{
			name[index] = '0';
			break;
		}
		case 1:
		{
			name[index] = '1';
			break;
		}
		case 2:
		{
			name[index] = '2';
			break;
		}
		case 3:
		{
			name[index] = '3';
			break;
		}
		case 4:
		{
			name[index] = '4';
			break;
		}
		case 5:
		{
			name[index] = '5';
			break;
		}
		case 6:
		{
			name[index] = '6';
			break;
		}
		case 7:
		{
			name[index] = '7';
			break;
		}
		case 8:
		{
			name[index] = '8';
			break;
		}
		case 9:
		{
			name[index] = '9';
			break;
		}
		default:
			Print("Error: Sprintf incorrect id\n");
	}/*end of switch case*/

}

/* Sprintf code */
int Sprintf(char *idName, int id, int len)
{
	int i;
	int id1, id2;
	for(i=0; i<len; i++)
	{
		name[i] = idName[i];
	}
	/*Warning: maximum number for id is 99 */
	if(id<=9){
		SwitchSprintf(id, i);
		i++;
		name[i]='\0';
	}
	else if((id>=10) && (id<=99)){
		id1 = id/10;
		SwitchSprintf(id1, i);
		i++;
		id2 = id%10;
		SwitchSprintf(id2, i);
		i++;
		name[i]='\0';
	}
	else{
		Print("Error: Sprintf incorrect id. greater than 99");
		return -1;
	}
	return i;
}
/*
//============================================
//  Functions for the repeatable test cases
//============================================


//This part of the code generates the common test parameters needed for the simulation to run
// i.e. Condition Variables , Monitors & Locks*/
void generateCmnTestParams()
{
	int i=0,j=0;
	int len;



	Acquire(printLock);
	Print1("\n\nNumber of Clerks = [%d]\n",noOfClerks);
	Print1("Number of StockBoys = [%d]\n",noOfStockBoys);
	Print1("Number of CashRegisters = [%d]\n",noOfCashReg);
	Print1("Number of Customers = [%d]\n",noOfCustomers);
	Print("Number of Managers = [1]\n");
	Print("Number of Aisle = [10]\n");
    Print("Items:\n");
    Print("\tNumber - Price\n");

	for(j=0;j<MAX_NO_OF_AISLE;j++)
	{
		Print2("\t%d  -  %d  \n",j,itemsInStoreInfo[j]);
	}
    Print("\n\n");
	Release(printLock);

	
	clerkLineLock= CreateLock("clerkLineLock",13);	
	sbStatusLock = CreateLock("sbStatusLock",12);
	stockRoomLock = CreateLock("stockRoomLock",13);
	stockRoomWaitCV = CreateCondition("stockRoomWaitCV",15);
	reStockListLock = CreateLock("reStockListLock",15);
	custWaitingCV = CreateCondition("custWaitingCV",13);
	for(i=0;i<MAX_NO_OF_AISLE;i++)
	{
		len = Sprintf("aisleQtyLock",i,12);
		aisleQtyLock[i]=CreateLock(name , len);
		
		len = Sprintf("aisleEmptyCV",i,12);
		aisleEmptyCV[i]=CreateCondition(name, len);
		
		len = Sprintf("aisleHelpCV",i,11);
		aisleHelpCV[i]=CreateCondition(name, len);
	}

	noSBPushButtonLock =CreateLock("noSBPushButtonLock",18);
	noSBPushButtonCV = CreateCondition("noSBPushButtonCV",16);

	sbOnBreakCV = CreateCondition("sbOnBreakCV",11);
	for(i=0;i<noOfStockBoys;i++)
	{
		len = Sprintf("sbLock",i,6);
		sbLock[i]=CreateLock(name, len);
		
		len = Sprintf("sbCV",i,4);
		sbCV[i]=CreateCondition(name, len);

	}
	for(i=0;i<noOfClerks;i++)
	{
		len = Sprintf("clerkLock",i,9);
		clerkLock[i]=CreateLock(name, len);

		len = Sprintf("clerkLineCV",i,11);
		clerkLineCV[i]=CreateCondition(name, len);

		len = Sprintf("clerkTalkCV",i,11);
		clerkTalkCV[i]=CreateCondition(name, len);
	}

	for(i=0;i<noOfCashReg;i++)
	{
		len = Sprintf("cashRegisterCV",i,14);
		cashRegisterCV[i]=CreateCondition(name, len);

		len = Sprintf("manager_CashRegisterLock",i,24);
		manager_CashRegisterLock[i]=CreateLock(name, len);
		
		len = Sprintf("cashRegisterWaitingCV",i,21);
		cashRegisterWaitingCV[i]=CreateCondition(name, len);
	}

	

	clerkOnBreakCV=CreateCondition("clerkOnBreakCV",14);

	for(i=0;i<MAX_NO_OF_CUSTOMERS;i++)
	{
		customerData[i].noOfItemsToBePurchased=(int)((GetRand()%10)+1);
		for(j=0;j<customerData[i].noOfItemsToBePurchased;j++)
		{
			customerData[i].itemsToBePurchased[j]=(int)(GetRand()%10);
		}
		if(GetRand()%5==4){
			customerData[i].customerReturning=TRUE;
		}
		else{
			customerData[i].customerReturning=FALSE;
		}
	}
	


	/* Create Monitor variables*/
	custThreadCntr = CreateMV("custThreadCntr",14,0);
	cashRegThreadCntr = CreateMV("cashRegThreadCntr",17,0);
	clerkThreadCntr = CreateMV("clerkThreadCntr",15,0);
	sbThreadCntr = CreateMV("sbThreadCntr",12,0);

	for(i=0; i<MAX_NO_OF_CASHREGISTERS; i++){
		len = Sprintf("clerkLineLength",i,15);
		clerkLineLength[i] = CreateMV(name, len, 0);
	}

	for(i=0; i<MAX_NO_OF_CLERKS; i++){
		len = Sprintf("clerkStatus",i,11);
		clerkStatus[i] = CreateMV(name, len, CLERK_FREE);
	}

	for(i=0; i<MAX_NO_OF_CLERKS; i++){
		len = Sprintf("itemId",i,6);
		itemId[i] = CreateMV(name, len, -1);
	}

	for(i=0; i<MAX_NO_OF_CLERKS; i++){
		len = Sprintf("lastItem",i,8);
		lastItem[i] = CreateMV(name, len, FALSE);
	}

	for(i=0; i<MAX_NO_OF_CLERKS; i++){
		len = Sprintf("customerId",i,10);
		customerId[i] = CreateMV(name, len, -1);
	}

	for(i=0; i<MAX_NO_OF_CLERKS; i++){
		len = Sprintf("receiptBillAmount",i,17);
		receiptBillAmount[i] = CreateMV(name, len, -1);
	}

	for(i=0; i<MAX_NO_OF_CLERKS; i++){
		len = Sprintf("isCustomerReturning",i,19);
		isCustomerReturning[i] = CreateMV(name, len, FALSE);
	}

	signalingClerk = CreateMV("signalingClerk", 14, -1);


	for(i=0; i<MAX_NO_OF_CASHREGISTERS; i++){
		len = Sprintf("cr_customerAmount",i,17);
		cr_customerAmount[i] = CreateMV(name, len, 0);

		len = Sprintf("cr_totalAmount",i,14);
		cr_totalAmount[i] = CreateMV(name, len, 0);

		len = Sprintf("cr_totalSalesAtCashRegister",i,27);
		cr_totalSalesAtCashRegister[i] = CreateMV(name, len, 0);
	}

	for(i=0; i<MAX_NO_OF_CASHREGISTERS; i++){
		len = Sprintf("cashRegisterStatus",i,18);
		cashRegisterStatus[i] = CreateMV(name, len, NOT_SET);

		len = Sprintf("amountNeeded",i,12);
		amountNeeded[i] = CreateMV(name, len, 0);
	}


	noSBPushButtonLineLength = CreateMV("noSBPushButtonLineLength",24,0);

	totalcustomersexited = CreateMV("totalcustomersexited",20,0);

	wakeUpAClerk = CreateMV("wakeUpAClerk",12,FALSE);

	allClerksOnBreak = CreateMV("allClerksOnBreak",16,FALSE);

	stockRoomStatus = CreateMV("stockRoomStatus",15,-1);


	for(i=0; i<MAX_NO_OF_AISLE; i++){
		len = Sprintf("aisleQty",i,8);
		aisleQty[i] = CreateMV(name, len, 3);

		len = Sprintf("aisleHelpLineLength",i,19);
		aisleHelpLineLength[i] = CreateMV(name, len, 0);
	}


	for(i=0; i<MAX_NO_SB; i++){
		len = Sprintf("sbStatus",i,8);
		sbStatus[i] = CreateMV(name, len, -1);
	}


	for(i=0; i<MAX_NO_SB; i++){
		len = Sprintf("sbCustQA0",i,9);
		sbCustQA[i][0] = CreateMV(name, len, 0);

		len = Sprintf("sbCustQA1",i,9);
		sbCustQA[i][1] = CreateMV(name, len, 0);
	}


	Fork(Manager);

	for(i=0;i<noOfStockBoys;i++)
	{
		Fork(StockBoy);
	}

	for(i=0;i<noOfCustomers;i++)
	{
		Fork(Customer);
	}


	for(i=0;i<noOfClerks;i++)
	{
		Fork(Clerk);
	}

	for(i=0;i<noOfCashReg;i++)
	{
		Fork(CashReg);
	}


}




/*This test case runs the entire simulation with minimum requirements*/
void testcase12()
{

	
	noOfClerks=3;
	noOfCashReg=3;
	noOfCustomers=20;
	noOfStockBoys=3;

	generateCmnTestParams();
}




/*====================================================================================
// Function Problem2() which is called for simulation of the Part 2 of Assignment 1
// Contains the Test Case Selection Menu in it.
//====================================================================================*/


void main()
{
	

	printLock = CreateLock("printLock",9);
	custThreadCntrLock=CreateLock("custThreadCntrLock",18);
	cashRegThreadCntrLock=CreateLock("cashRegThreadCntrLock",21);
	clerkThreadCntrLock=CreateLock("clerkThreadCntrLock",19);
	sbThreadCntrLock=CreateLock("sbThreadCntrLock",16);

	/* Call testcase with minimum requiements */
	testcase12();

Exit(0);
}
